package com.onlyxiahui.common.utils.base.lang.reflect;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * 
 * Date 2019-03-30 17:16:59<br>
 * Description 反射工具
 * 
 * @author XiaHui<br>
 * @since 1.0.0
 */
public class ReflectUtil {

	/**
	 * 
	 * Description 获取所有字段 <br>
	 * Date 2020-11-10 15:18:27<br>
	 * 
	 * @param clazz
	 * @return
	 * @since 1.0.0
	 */
	public static List<Field> getFieldList(Class<?> clazz) {
		List<Field> list = new ArrayList<>();
		if (null != clazz) {
			Field[] fields = clazz.getDeclaredFields();
			for (int i = 0; i < fields.length; i++) {
				list.add(fields[i]);
			}
		}
		return list;
	}

	/**
	 * 
	 * Description 获取所有字段<br>
	 * Date 2020-11-10 15:23:40<br>
	 * 
	 * @param clazz
	 * @param rootClass ：如果为空一直找到Object.class
	 * @return
	 * @since 1.0.0
	 */
	public static List<Field> getFieldList(Class<?> clazz, Class<?> rootClass) {
		List<Field> list = getFieldList(clazz);
		// 并且顶层rootClass不等于当前
		if (clazz != rootClass) {

			Set<String> set = new HashSet<>();
			for (Field f : list) {
				set.add(f.getName());
			}

			Class<?> superClass = clazz.getSuperclass();
			List<Field> fields = getFieldList(superClass);

			for (Field f : fields) {
				if (!set.contains(f.getName())) {
					set.add(f.getName());
					list.add(f);
				}
			}
			boolean isRoot = (superClass == rootClass);

			while (!isRoot) {
				superClass = superClass.getSuperclass();
				fields = getFieldList(superClass);
				for (Field f : fields) {
					if (!set.contains(f.getName())) {
						set.add(f.getName());
						list.add(f);
					}
				}
				isRoot = (superClass == rootClass);
			}
		}
		return list;
	}

	/**
	 * 
	 * Date 2019-03-30 17:13:01<br>
	 * Description 获取class中的字段
	 * 
	 * @param clazz
	 * @param name
	 * @return Field
	 * @since 1.0.0
	 */
	public static Field getField(Class<?> clazz, String name) {
		if (null != clazz && null != name) {
			Field[] fields = clazz.getDeclaredFields();
			String internedName = name.intern();
			for (int i = 0; i < fields.length; i++) {
				boolean is = null != fields[i] && (fields[i].getName() == internedName || fields[i].getName().equals(internedName));
				if (is) {
					return fields[i];
				}
			}
		}
		return null;
	}

	/**
	 * 
	 * Description 深度查找Class的属性Field,当前class没找到就继续找父类<br>
	 * Date 2019-03-30 17:11:57<br>
	 * 
	 * @param clazz
	 * @param rootClass :为设定最顶层的父类，找到此类就不继续了，默认为Object
	 * @param name
	 * @return Field
	 * @since 1.0.0
	 */
	public static Field getField(Class<?> clazz, Class<?> rootClass, String name) {
		Field field = getField(clazz, name);
		// 如果字段不存在，并且顶层rootClass不等于当前
		if (null == field && clazz != rootClass) {
			Class<?> superClass = clazz.getSuperclass();
			field = getField(superClass, name);
			boolean isRoot = superClass == rootClass;

			while (!isRoot && null == field) {
				superClass = superClass.getSuperclass();
				field = getField(superClass, name);
				isRoot = superClass == rootClass;
			}
		}
		return field;
	}

	/**
	 * 
	 * Date 2019-03-30 17:16:00<br>
	 * Description 获取data对象fieldName的Field
	 * 
	 * @param data
	 * @param fieldName
	 * @return Field
	 * @since 1.0.0
	 */
	public static Field getField(Object data, String fieldName) {
		Field field = getField(data.getClass(), fieldName);
		return field;
	}

	/**
	 * Description 获取属性的值
	 * 
	 * @param data
	 * @param field
	 * @return Object
	 */
	public static Object getFieldValue(Object data, Field field) {
		Object value = null;
		if (null != field) {
			// 使对象的属性可访问
			try {
				boolean isAccessible = field.isAccessible();
				if (!isAccessible) {
					field.setAccessible(true);
				}
				value = field.get(data);
				if (!isAccessible) {
					field.setAccessible(isAccessible);
				}
			} catch (IllegalArgumentException | IllegalAccessException e) {
				e.printStackTrace();
			}
		}
		return value;
	}

	/**
	 * 
	 * Date 2019-03-30 17:16:19<br>
	 * Description 获取data对象fieldName的属性值
	 * 
	 * @param data
	 * @param fieldName
	 * @return Object
	 * @since 1.0.0
	 */
	public static Object getFieldValue(Object data, String fieldName) {
		Field field = getField(data, fieldName);
		return getFieldValue(data, field);
	}

	/**
	 * 
	 * Date 2019-03-30 17:16:42<br>
	 * Description 设置data对象fieldName的属性值
	 * 
	 * @param data
	 * @param fieldName
	 * @param value
	 * @since 1.0.0
	 */
	public static void setFieldValue(Object data, Field field, Object value) {
		try {
			if (null != data && null != field && null != value) {
				if (field.isAccessible()) {
					field.set(data, value);
				} else {
					field.setAccessible(true);
					field.set(data, value);
					field.setAccessible(false);
				}
			}
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 
	 * Date 2019-03-30 17:16:42<br>
	 * Description 设置data对象field的属性值
	 * 
	 * @param data
	 * @param fieldName
	 * @param value
	 * @since 1.0.0
	 */
	public static void setFieldValue(Object data, String fieldName, Object value) {
		Field field = getField(data, fieldName);
		setFieldValue(data, field, value);
	}
}
